import org.eclipse.swt.widgets.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.apache.commons.mail.EmailException;

import java.io.IOException;

public class MainWindow
{
    static class ItemList
    {
        public ItemList(Shell shell, String name, int x, int w, int h)
        {
            list = new List(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);

            label = new Label(shell, SWT.NATIVE);

            add = new Button(shell, SWT.PUSH);
            remove = new Button(shell, SWT.PUSH);
            edit = new Button(shell, SWT.PUSH);

            label.setText(name+":");
            add.setText("new");
            remove.setText("remove");
            edit.setText("edit");

            label.setBounds(x, 30, w, 20);
            list.setBounds(x, 50, w, h);

            int bh = 30;

            edit.setBounds(x+10,   h + 60,          w - 20, bh - 5);
            add.setBounds(x+10,    h + 60 + bh,     w - 20, bh - 5);
            remove.setBounds(x+10, h + 60 + 2*bh,   w - 20, bh - 5);
        }

        public List list;
        public Label label;
        public Button add, remove, edit;
    }

    public abstract class ItemListHandler
    {
        public ItemListHandler(ItemList target)
        {
            target.list.addSelectionListener(new SelectionAdapter()
            {   public void widgetSelected(SelectionEvent e) { hilight(); } } );
            target.add.addSelectionListener(new SelectionAdapter()
            {   public void widgetSelected(SelectionEvent e) { add(); } } );
            target.remove.addSelectionListener(new SelectionAdapter()
            {   public void widgetSelected(SelectionEvent e) { remove(); } } );
            target.edit.addSelectionListener(new SelectionAdapter()
            {   public void widgetSelected(SelectionEvent e) { modify(); } } );
        }

        abstract void add();
        abstract void modify();
        abstract void remove();
        abstract void hilight();
    }

    public MainWindow(Judicator k)
    {
        judicator = k;
        k.mainWindow = this;

        display = new Display();
        shell = new Shell(display, SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX);
        shell.setText("Judicator v0.3");

        AlertSender.init(shell);

        students = new ItemList(shell, "students", 20, 200, 500);
        teams = new ItemList(shell, "teams", 230, 200, 300);
        tasks = new ItemList(shell, "tasks", 440, 200, 300);
        issues = new ItemList(shell, "issues", 650, 520, 500);

        menu = new Menu (shell, SWT.BAR);
        shell.setMenuBar(menu);

        fileMenu = new Menu(shell, SWT.DROP_DOWN);
        toolsMenu = new Menu(shell, SWT.DROP_DOWN);

        fileItem = new MenuItem (menu, SWT.CASCADE);
        fileItem.setText ("&File");
        fileItem.setMenu(fileMenu);

        toolsItem = new MenuItem (menu, SWT.CASCADE);
        toolsItem.setText ("&Tools");
        toolsItem.setMenu(fileMenu);        

        MenuItem nuke = new MenuItem (fileMenu, SWT.PUSH);
        nuke.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {nuke();} });
        nuke.setText ("&New\tCtrl+N");
        nuke.setAccelerator(SWT.MOD1 + 'N');

        MenuItem load = new MenuItem(fileMenu, SWT.PUSH);
        load.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {load();} });
        load.setText ("&Open\tCtrl+O");
        load.setAccelerator(SWT.MOD1 + 'O');

        MenuItem saveAs = new MenuItem(fileMenu, SWT.PUSH);
        saveAs.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {saveAs();} });
        saveAs.setText ("Save &As...");

        MenuItem save = new MenuItem(fileMenu, SWT.PUSH);
        save.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {save();} });
        save.setText ("&Save\tCtrl+S");
        save.setAccelerator(SWT.MOD1 + 'S');

        MenuItem settings = new MenuItem(toolsMenu, SWT.PUSH);
        settings.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {settings();} });
        settings.setText ("Settings...");


        makeHtml = new Button(shell, SWT.NATIVE);
        makeHtml.setText("Write Feedback");
        makeHtml.setBounds(250,570,110,35);
        makeHtml.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {writeFeedback();} });

        sendEmails = new Button(shell, SWT.NATIVE);
        sendEmails.setText("Send Email");
        sendEmails.setBounds(380,570,110,35);
        sendEmails.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {sendMails();} });

        showPoints = new Button(shell, SWT.NATIVE);
        showPoints.setText("Show Points");
        showPoints.setBounds(510,570,110,35);
        showPoints.addListener (SWT.Selection, new Listener ()
        {   public void handleEvent (Event e) {showPoints();} });


        titleLabel = new Label(shell, SWT.SHADOW_OUT);
        titleLabel.setText("title:");
        titleLabel.setBounds(250, 500, 60, 25);
        title = new Text(shell, SWT.BORDER);
        title.setEditable(true);
        title.setBounds(250, 525, 370, 25);

        studentHandler = new StudentHandler();
        teamHandler = new TeamHandler();
        taskHandler = new TaskHandler();
        issueHandler = new IssueHandler();

        shell.setBounds(20,20,1200,720);
        shell.setMinimumSize(1200,720);
        shell.pack();
        shell.open();

        while (!shell.isDisposed())
        {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }

    ItemList tasks, students, teams, issues;
    Display display;
    Shell shell;
    Menu menu, fileMenu, toolsMenu;
    MenuItem fileItem, toolsItem;
    Button makeHtml, showPoints, sendEmails;
    Label titleLabel;
    Text title;

    StudentEditor studentEditor = null;
    TaskEditor taskEditor = null;
    TeamEditor teamEditor = null;
    IssueEditor issueEditor = null;

    Judicator judicator;

    StudentHandler studentHandler;
    TeamHandler teamHandler;
    TaskHandler taskHandler;
    IssueHandler issueHandler;

    String filename = "";

    public class StudentHandler extends ItemListHandler
    {
        public StudentHandler()
        {
            super(students);
        }

        void add()
        {
            if (studentEditor != null) studentEditor.close();
            studentEditor = new StudentEditor(judicator, shell, "add student", null);
        }

        void modify()
        {
            int index = students.list.getSelectionIndex();
            if (index < 0) return;

            if (studentEditor != null) studentEditor.close();
            studentEditor = new StudentEditor(judicator, shell, "edit student", judicator.students.get(index));
        }

        void remove()
        {
            int[] sel = students.list.getSelectionIndices();
            students.list.remove(sel);
            judicator.removeStudents(sel);
        }

        void hilight()
        {
            int index = students.list.getSelectionIndex();
            if (index < 0) return;

            Student s = judicator.getStudent(students.list.getItem(index));
            if (s != null && s.team != null)
            {
                String[] tn = {s.team.getLabel()};
                teams.list.setSelection(tn);

                issues.list.setSelection(new int[]{});
                for (Issue i : s.team.issues)
                {
                    issues.list.select(judicator.issues.indexOf(i));
                }
            }
            else
            {
                teams.list.setSelection(new int[]{});
            }
        }
    }

    public class TeamHandler extends ItemListHandler
    {
        public TeamHandler()
        {
            super(teams);
        }

        void add()
        {
            if (teamEditor != null) teamEditor.close();
            teamEditor = new TeamEditor(judicator, shell, "add team", null);
        }

        void modify()
        {
            int index = teams.list.getSelectionIndex();
            if (index < 0) return;

            if (teamEditor != null) teamEditor.close();
            teamEditor = new TeamEditor(judicator, shell, "edit team", judicator.teams.get(index));
        }

        void remove()
        {
            int[] sel = teams.list.getSelectionIndices();
            teams.list.remove(sel);
            judicator.removeTeams(sel);
        }

        void hilight()
        {
            int selected = teams.list.getSelectionIndex();
            if (selected < 0) return;

            Team t = judicator.teams.get(selected);

            students.list.setSelection(new int[]{});
            issues.list.setSelection(new int[]{});
            for (Student s : t.students) students.list.select(judicator.students.indexOf(s));
            for (Issue i : t.issues) issues.list.select(judicator.issues.indexOf(i));
        }
    }

    public class TaskHandler extends ItemListHandler
    {
        public TaskHandler()
        {
            super(tasks);
        }

        void add()
        {
            if (taskEditor != null) taskEditor.close();
            taskEditor = new TaskEditor(judicator, shell, "add task", null);
        }


        void modify()
        {
            int index = tasks.list.getSelectionIndex();
            if (index < 0) return;

            if (taskEditor != null) taskEditor.close();
            taskEditor = new TaskEditor(judicator, shell, "edit task", judicator.tasks.get(index));
        }

        void remove()
        {
            int[] sel = tasks.list.getSelectionIndices();
            tasks.list.remove(sel);
            judicator.removeTasks(sel);
        }

        void hilight()
        {
            int selected = tasks.list.getSelectionIndex();
            if (selected < 0) return;

            Task t = judicator.tasks.get(selected);

            issues.list.setSelection(new int[]{});
            for (Issue i : judicator.issues)
            {
                if (i.task == t) issues.list.select(judicator.issues.indexOf(i));
            }
        }
    }

    public class IssueHandler extends ItemListHandler
    {
        public IssueHandler()
        {
            super(issues);
        }

        void add()
        {
            if (issueEditor != null) issueEditor.close();
            issueEditor = new IssueEditor(judicator, shell, "add issue", null);
        }

        void modify()
        {
            int index = issues.list.getSelectionIndex();
            if (index < 0) return;

            if (issueEditor != null) issueEditor.close();
            issueEditor = new IssueEditor(judicator, shell, "edit issue", judicator.issues.get(index));
        }

        void remove()
        {
            int[] sel = issues.list.getSelectionIndices();
            issues.list.remove(sel);
            judicator.removeIssues(sel);
        }

        void hilight()
        {
            int selected = issues.list.getSelectionIndex();
            if (selected < 0) return;

            Issue s = judicator.issues.get(selected);

            teams.list.setSelection(new int[]{});
            students.list.setSelection(new int[]{});
            for (Team t : s.teams)
            {
                teams.list.select(judicator.teams.indexOf(t));
                for (Student d : t.students) students.list.select(judicator.students.indexOf(d));
            }
        }
    }

    public void saveAs()
    {
        FileFormat f = new FileFormat();
        FileDialog fd = new FileDialog(shell, SWT.SAVE | SWT.APPLICATION_MODAL);
        fd.open();
        filename = fd.getFileName();

        if (filename.length() > 0) f.write(judicator, filename);
    }

    public void save()
    {
        if (filename.length() == 0) saveAs();
        else (new FileFormat()).write(judicator, filename);
    }

    public void load()
    {
        FileFormat f = new FileFormat();
        FileDialog fd = new FileDialog(shell, SWT.OPEN | SWT.APPLICATION_MODAL);
        fd.open();
        filename = fd.getFileName();

        if (filename.length() > 0) f.read(judicator, filename);
    }

    public void nuke()
    {
        filename = "";
        judicator.clearAll();
    }



    public void writeFeedback()
    {
        Progress p = new Progress(judicator.teams.size(), shell);

        HtmlReportWriter rw = new HtmlReportWriter();
        PlainReportWriter prw = new PlainReportWriter();

        for (Team t : judicator.teams)
        {
        	if (t.students.size() == 0) continue;
            try
            {
                boolean allHtml = true;
                for (Student s : t.students)
                {
                    if (s.preferredFormat != Student.HTML)
                    {
                        allHtml = false;
                        break;
                    }
                }

                rw.writeReport(t, title.getText(), judicator);
                if (!allHtml) prw.writeReport(t, title.getText(), judicator);
            }
            catch (IOException e)
            {
                AlertSender.sendAlert("unable to write to file: " + e.getMessage());
                e.printStackTrace();
            }

            p.step();

        }

        p.dispose();
    }

    public void showPoints()
    {
        new PointsDisplay(shell, judicator);
    }

    public void settings()
    {
        
    }

    public void sendMails()
    {
        new LoginBox(shell);

        Progress p = new Progress(judicator.teams.size(), shell);

        ReportMailer rm = new ReportMailer();
        for (Team t : judicator.teams)
        {
        	if (t.students.size() == 0) continue;
            try
            {
                rm.sendReport(t, title.getText(), Settings.getEmailSubject(), judicator);
            }
            catch (EmailException e)
            {
                AlertSender.sendAlert("Unable to send mail: " + e.getCause());
                e.printStackTrace();
            }

            p.step();
        }

        p.dispose();
    }
}
